package LatentTicTacToe.Calculators;

import LatentTicTacToe.Data.Move;
import LatentTicTacToe.InformationSets.CFRInformationSet;

public class LTTTStrategyCalculator extends StrategyCalculator {

	public LTTTStrategyCalculator() {
	}

	@Override
	public void updateStrategy(int iteration) {
		updateStrategy("", iteration);
	}

	/**
	 * Updates strategy in every information set
	 * 
	 * @param id
	 * @param iteration
	 */
	private void updateStrategy(String id, int iteration) {

		CFRInformationSet set = gameTree.get(id);

		if (set == null) {
			return;
		}

		if (set.winner != 0) {
			return;
		}

		if (set.currentPlayer == 1) {
			if(id.equals("")) {
				set.setProbability(1);
			}
			updateStrategyForMaxPlayer(iteration, set);
		} else {
			updateStrategyForMinPlayer(iteration, set);
		}

		if (id.equals("")) {
			updateStrategy("0", iteration);
		} else {
			for (Move move : set.moves) {
				updateStrategy(addMoveToId(id, move.toString()), iteration);
				updateSingleStateStrategy(addMoveToId(addMoveToId(id, move.toString()), move.toString()), iteration);
			}
		}

	}

	private void updateStrategyForMinPlayer(int iteration, CFRInformationSet set) {

		float[] currentRegret = set.regret;
		float[] currentStrategy = set.getStrategy();
		float setValue = 0;
		float sum = 0;

		for (int i = 0; i < set.values.length; i++) {
			setValue += set.values[i] * set.getStrategy()[i];
		}

		for (int i = 0; i < set.regret.length; i++) {
			currentRegret[i] += set.getProbability() * (set.values[i] - setValue);
			sum += Math.min(currentRegret[i] / iteration, 0);
		}

		for (int i = 0; i < currentStrategy.length; i++) {
			currentStrategy[i] = (sum < 0) ? Math.min(currentRegret[i] / iteration, 0) / sum : 1 / (float) currentRegret.length;
		}
	}

	private void updateStrategyForMaxPlayer(int iteration, CFRInformationSet set) {

		float[] currentRegret = set.regret;
		float[] currentStrategy = set.getStrategy();
		float setValue = 0;
		float sum = 0;
		
		for (int i = 0; i < set.values.length; i++) {
			setValue += set.values[i] * set.getStrategy()[i];
		}

		for (int i = 0; i < set.regret.length; i++) {
			currentRegret[i] += set.getProbability() * (set.values[i] - setValue);
			sum += Math.max(currentRegret[i] / iteration, 0);
		}

		for (int i = 0; i < currentStrategy.length; i++) {
			currentStrategy[i] = (sum > 0) ? Math.max(currentRegret[i] / iteration, 0) / sum : 1 / (float) currentRegret.length;
		}
	}

	private void updateSingleStateStrategy(String id, int iteration) {

		CFRInformationSet set = gameTree.get(id);

		if (set == null) {
			return;
		}

		if (set.currentPlayer == 1) {
			updateStrategyForMaxPlayer(iteration, set);
		} else {
			updateStrategyForMinPlayer(iteration, set);
		}
	}

	private String addMoveToId(String id, String move) {

		StringBuilder builder = new StringBuilder();

		builder.append(id);
		builder.append(".");
		builder.append(move);

		return builder.toString();
	}

}
